#include "../util/structure.h"
#include <stdio.h>
static FILE * output=NULL;

static void set_output(FILE * f){
    output = f;
    return;
}

static void opl(Operand x){fprintf(output,"L%u",x.label);}
static void opv(Operand x){
    if(x.var.addr_status==CONSTANT_ID) fprintf(output,"#%d",x.var.no);
    else{
        for(;x.var.addr_status<0;x.var.addr_status++) fputc('&',output);
        for(;x.var.addr_status>0;x.var.addr_status--) fputc('*',output);
        fprintf(output,"a%u",x.var.no);
    }
}
static void opn(uLL x){
    const char * ch=(const char *)x;
    if(strcmp(ch,"main")==0) fprintf(output,"main");
    else fprintf(output,"f_%s",ch);
}
static void ops(const char * s){while(*s) fputc(*(s++),output);}
static void opr(int x){
    switch (x){
        case IR_RELOP_GE: ops(" >= ");break;
        case IR_RELOP_LE: ops(" <= ");break;
        case IR_RELOP_EQ: ops(" == ");break;
        case IR_RELOP_NE: ops(" != ");break;
        case IR_RELOP_LT: ops(" < ");break;
        case IR_RELOP_GT: ops(" > ");break;
    }
}

static void opstatement(operation s){
    Operand x=s.x,y=s.y,z=s.z;

    switch(s.op){
        case OP_LABEL: ops("LABEL ");opl(x);ops(" :"); break;
        case OP_ASSIGN: opv(x); ops(" := "); opv(y); break;
        case OP_ADD: opv(x); ops(" := "); opv(y); ops(" + ");opv(z); break;
        case OP_SUB: opv(x); ops(" := "); opv(y); ops(" - ");opv(z); break;
        case OP_MUL: opv(x); ops(" := "); opv(y); ops(" * ");opv(z); break;
        case OP_DIV: opv(x); ops(" := "); opv(y); ops(" / ");opv(z); break;
        case OP_GOTO: ops("GOTO ");opl(x); break;
        case OP_IF: ops("IF "); opv(x); opr(s.info); opv(y); ops(" GOTO "); opl(z); break;
        case OP_RET: ops("RETURN "); opv(x); break;
        case OP_DEC: ops("DEC "); opv(x); fprintf(output," %llu",s.info); break;
        case OP_ARG: ops("ARG "); opv(x); break;
        case OP_CALL: opv(x); ops(" := CALL "); opn(s.info); break;
        case OP_READ: ops("READ "); opv(x); break;
        case OP_WRITE: ops("WRITE "); opv(x); break;
    }
    ops("\n");
}

void output_all(FILE * f){
    set_output(f);
    FOR_LIST(iter,function_list){
        function * func=LIST_GET(iter,function *);
        ops("FUNCTION ");opn((uLL)func->name); ops(" :\n");
        FOR_LIST(param,func->param) 
            fprintf(output,"PARAM a%llu\n",LIST_GET(param, uLL));
        FOR_LIST(block,func->BBlist){
            if(func->BBlist.begin!=block&&LIST_EMPTY(LIST_GET(block,BB*)->entry)) continue;
            FOR_LIST(s,LIST_GET(block,BB *)->statement)
            opstatement(*LIST_GET(s,operation *));
        }
        
    }
}